﻿// ***********************************************************************
// Assembly         : OSS.BIM
// Author           : tian_
// Created          : 09-03-2018
//
// Last Modified By : tian_
// Last Modified On : 09-05-2018
// ***********************************************************************
// <copyright file="BmTreeListManager.cs" company="北京智帆高科科技有限公司">
//     Copyright © 北京智帆高科科技有限公司 2018
// </copyright>
// <summary></summary>
// ***********************************************************************
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using OSS.BIM.Business.Utility;
using OSS.BIM.Model;
using OSS.BIM.Properties;
using DevExpress.XtraTreeList;
using DevExpress.XtraTreeList.Nodes;
using OSS.BIM.Business;
using ZFGK.DevExprss.Controls;
using ZFGK.DevExprss.Utility;
using ZFGK.osgEarth.UI;
using ZFGK.Utility;

namespace OSS.BIM.Utility
{
    /// <summary>
    /// Class BmTreeListManager.
    /// </summary>
    public static class BmTreeListManager
    {
        /// <summary>
        /// The tree list
        /// </summary>
        public static ZfTreeList treeList = new ZfTreeList();

        /// <summary>
        /// Gets the tree list.
        /// </summary>
        /// <value>The tree list.</value>
        public static TreeList TreeList
        {
            get { return treeList; }
        }

        #region 初始化
        /// <summary>
        /// Initializes the TreeView model.
        /// </summary>
        public static void InitTreeViewModel()
        {
            TreeList.BeginUpdate();

            TreeList.Nodes.Clear();

            var rootNode = TreeList.AppendNode(new object[] { "项目" }, null, null);
            rootNode.SetSelectImage(Resources.bullets);
            rootNode.SetImage(Resources.bullets);

            var projects = ProjectDbUtil.GetAll();
            foreach (var project in projects)
            {
                var treeListNode = TreeList.AppendNode(new object[] { project.Name }, rootNode, project);
                treeListNode.SetSelectImage(Resources.project);
                treeListNode.SetImage(Resources.project);
                AddChild(treeListNode, project.GetModelGropes());
            }

            TreeList.EndUpdate();
        }

        /// <summary>
        /// Adds the child.
        /// </summary>
        /// <param name="parentNode">The parent node.</param>
        /// <param name="modelGropes">The model gropes.</param>
        public static void AddChild(TreeListNode parentNode, IList<ModelGrope> modelGropes)
        {
            foreach (var modelGrope in modelGropes)
            {
                var treeListNode = parentNode.TreeList.AppendNode(new object[] { modelGrope.Name }, parentNode, modelGrope);
                treeListNode.SetSelectImage(Resources.Folder);
                treeListNode.SetImage(Resources.Folder);
                AddChild(treeListNode, modelGrope.GetSimpleModelInfos());
            }
        }

        /// <summary>
        /// Adds the child.
        /// </summary>
        /// <param name="parentNode">The parent node.</param>
        /// <param name="modelInfos">The model infos.</param>
        public static void AddChild(TreeListNode parentNode, IList<ModelElement> modelInfos, bool nodeChecked = false)
        {
            foreach (var modelElement in modelInfos)
            {
                var treeListNode = parentNode.TreeList.AppendNode(new object[] { modelElement.Name }, parentNode, modelElement);
                treeListNode.Checked = nodeChecked;
                treeListNode.SetSelectImage(Resources.objects);
                treeListNode.SetImage(Resources.objects);
            }
        }
        #endregion

        #region 复选框

        /// <summary>
        /// Trees the list on after check node.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="args">The <see cref="NodeEventArgs" /> instance containing the event data.</param>
        public static void BmTreeListOnAfterCheckNode(object sender, NodeEventArgs args)
        {
            var activeEarthViewForm = BimManagerApp.ActiveEarthViewForm;
            if (activeEarthViewForm == null)
                return;
            var osgEarthObj = activeEarthViewForm.OsgEarthViewCtrl.OsgEarthObj;

            var argsNode = args.Node;

            // 先去掉回调，方式循环调用
            argsNode.TreeList.AfterCheckNode -= BmTreeListOnAfterCheckNode;

            argsNode.TreeList.BeginUpdate();
            string strMsg = null;
            try
            {
                LoadOrDeleteModelView(argsNode, osgEarthObj);
            }
            catch (Exception e)
            {
                strMsg = e.GetAllExMessage();
            }
            argsNode.TreeList.EndUpdate();

            MsgManager.AppendLine(strMsg);
            MsgManager.Show();

            // 加载回调
            argsNode.TreeList.AfterCheckNode += BmTreeListOnAfterCheckNode;
        }
        /// <summary>
        /// Loads the or delete model view.
        /// </summary>
        /// <param name="treeNode">The tree node.</param>
        public static void LoadOrDeleteModelView(TreeListNode treeNode, ZfOsgEarthObj osgEarthObj)
        {
            if (treeNode.Tag is ModelElement)
            {
                var modelElement = treeNode.Tag as ModelElement;
                if (treeNode.Checked)
                    osgEarthObj.AddOrReplaceModel(modelElement);
                else
                    osgEarthObj.DeleteModel(modelElement);
                Application.DoEvents();
            }
            foreach (TreeListNode treeNodeChild in treeNode.Nodes)
            {
                treeNodeChild.Checked = treeNode.Checked;
                LoadOrDeleteModelView(treeNodeChild, osgEarthObj);
            }
        }
        #endregion

        #region 查找节点
        /// <summary>
        /// Gets the parent tree list node.
        /// </summary>
        /// <param name="project">The project.</param>
        /// <returns>TreeListNode.</returns>
        public static TreeListNode GetParentTreeListNode(Project project)
        {
            return TreeList.Nodes.FirstNode;
        }

        /// <summary>
        /// Gets the tree list node.
        /// </summary>
        /// <param name="project">The project.</param>
        /// <returns>TreeListNode.</returns>
        public static TreeListNode GetTreeListNode(this Project project)
        {
            var parentNode = GetParentTreeListNode(project);
            if (parentNode == null)
                return null;

            return GetTreeListNode(parentNode, project);
        }

        /// <summary>
        /// Gets the tree list node.
        /// </summary>
        /// <param name="parentNode">The parent node.</param>
        /// <param name="project">The project.</param>
        /// <returns>TreeListNode.</returns>
        public static TreeListNode GetTreeListNode(TreeListNode parentNode, Project project)
        {
            var nodes = parentNode.Nodes;
            foreach (TreeListNode treeListNode in nodes)
            {
                Project fc = treeListNode.Tag as Project;
                if (fc != null && fc.ProjectId == project.ProjectId)
                {
                    return treeListNode;
                }
            }

            return null;
        }


        /// <summary>
        /// Gets the parent tree list node.
        /// </summary>
        /// <param name="modelGrope">The model grope.</param>
        /// <returns>TreeListNode.</returns>
        public static TreeListNode GetParentTreeListNode(this ModelGrope modelGrope)
        {
            return GetTreeListNode(modelGrope.GetProject());
        }


        /// <summary>
        /// Gets the tree list node.
        /// </summary>
        /// <param name="modelGrope">The model grope.</param>
        /// <returns>TreeListNode.</returns>
        public static TreeListNode GetTreeListNode(this ModelGrope modelGrope)
        {
            var parentNode = GetParentTreeListNode(modelGrope);
            if (parentNode == null)
                return null;

            return GetTreeListNode(parentNode, modelGrope);
        }


        /// <summary>
        /// Gets the tree list node.
        /// </summary>
        /// <param name="parentNode">The parent node.</param>
        /// <param name="modelGrope">The model grope.</param>
        /// <returns>TreeListNode.</returns>
        public static TreeListNode GetTreeListNode(TreeListNode parentNode, ModelGrope modelGrope)
        {
            var nodes = parentNode.Nodes;
            foreach (TreeListNode treeListNode in nodes)
            {
                ModelGrope fc = treeListNode.Tag as ModelGrope;
                if (fc != null && fc.ModelGropeId == modelGrope.ModelGropeId)
                {
                    return treeListNode;
                }
            }

            return null;
        }


        /// <summary>
        /// Gets the parent tree list node.
        /// </summary>
        /// <param name="modelElement">The model information.</param>
        /// <returns>TreeListNode.</returns>
        public static TreeListNode GetParentTreeListNode(this ModelElement modelElement)
        {
            return GetTreeListNode(modelElement.GetModelGrope());
        }


        /// <summary>
        /// Gets the tree list node.
        /// </summary>
        /// <param name="modelGrope">The model grope.</param>
        /// <returns>TreeListNode.</returns>
        public static TreeListNode GetTreeListNode(this ModelElement modelGrope)
        {
            var parentNode = GetParentTreeListNode(modelGrope);
            if (parentNode == null)
                return null;

            return GetTreeListNode(parentNode, modelGrope);
        }


        /// <summary>
        /// Gets the tree list node.
        /// </summary>
        /// <param name="parentNode">The parent node.</param>
        /// <param name="modelGrope">The model grope.</param>
        /// <returns>TreeListNode.</returns>
        public static TreeListNode GetTreeListNode(TreeListNode parentNode, ModelElement modelGrope)
        {
            var nodes = parentNode.Nodes;
            foreach (TreeListNode treeListNode in nodes)
            {
                ModelElement fc = treeListNode.Tag as ModelElement;
                if (fc != null && fc.ModelElementId == modelGrope.ModelElementId)
                {
                    return treeListNode;
                }
            }

            return null;
        }
        #endregion


        /// <summary>
        /// Adds the or update tree list node.
        /// </summary>
        /// <param name="project">The project.</param>
        /// <returns>TreeListNode.</returns>
        public static TreeListNode AddOrUpdateTreeListNode(this Project project)
        {
            var parentNode = GetParentTreeListNode(project);
            if (parentNode == null)
                return null;

            parentNode.TreeList.BeginUpdate();

            var treeListNode = parentNode.AddOrUpdateChild(new object[] { project.Name }, project, IsThisProjectCatalog);
            treeListNode.SetSelectImage(Resources.project);
            treeListNode.SetImage(Resources.project);

            parentNode.TreeList.EndUpdate();

            return treeListNode;
        }
        /// <summary>
        /// Determines whether [is this project catalog] [the specified node].
        /// </summary>
        /// <param name="node">The node.</param>
        /// <param name="tag">The tag.</param>
        /// <returns><c>true</c> if [is this project catalog] [the specified node]; otherwise, <c>false</c>.</returns>
        private static bool IsThisProjectCatalog(TreeListNode node, object tag)
        {
            var oldCatalog = node.Tag as Project;
            var newCatalog = tag as Project;
            if (oldCatalog == null || newCatalog == null)
                return false;
            return oldCatalog.ProjectId == newCatalog.ProjectId;
        }


        /// <summary>
        /// Adds the or update tree list node.
        /// </summary>
        /// <param name="modelGrope">The model grope.</param>
        /// <param name="nodeChecked">if set to <c>true</c> [node checked].</param>
        /// <returns>TreeListNode.</returns>
        public static TreeListNode AddOrUpdateTreeListNode(this ModelGrope modelGrope, bool nodeChecked = false)
        {
            var parentNode = GetParentTreeListNode(modelGrope);
            if (parentNode == null)
                return null;

            parentNode.TreeList.BeginUpdate();

            var treeListNode = parentNode.AddOrUpdateChild(new object[] { modelGrope.Name }, modelGrope, IsThisModelGropeCatalog);
            treeListNode.Checked = nodeChecked;
            treeListNode.SetSelectImage(Resources.Folder);
            treeListNode.SetImage(Resources.Folder);

            parentNode.TreeList.EndUpdate();

            return treeListNode;
        }
        /// <summary>
        /// Determines whether [is this model grope catalog] [the specified node].
        /// </summary>
        /// <param name="node">The node.</param>
        /// <param name="tag">The tag.</param>
        /// <returns><c>true</c> if [is this model grope catalog] [the specified node]; otherwise, <c>false</c>.</returns>
        private static bool IsThisModelGropeCatalog(TreeListNode node, object tag)
        {
            var oldCatalog = node.Tag as ModelGrope;
            var newCatalog = tag as ModelGrope;
            if (oldCatalog == null || newCatalog == null)
                return false;
            return oldCatalog.ModelGropeId == newCatalog.ModelGropeId;
        }




        /// <summary>
        /// Adds the or update tree list node.
        /// </summary>
        /// <param name="modelElement">The model information.</param>
        /// <returns>TreeListNode.</returns>
        public static TreeListNode AddOrUpdateTreeListNode(this ModelElement modelElement)
        {
            var parentNode = GetParentTreeListNode(modelElement);
            return AddOrUpdateTreeListNode(parentNode, modelElement);
        }

        /// <summary>
        /// Adds the or update tree list node.
        /// </summary>
        /// <param name="parentNode">The parent node.</param>
        /// <param name="modelElement">The model information.</param>
        /// <returns>TreeListNode.</returns>
        public static TreeListNode AddOrUpdateTreeListNode(TreeListNode parentNode, ModelElement modelElement)
        {
            if (parentNode == null)
                return null;

            parentNode.TreeList.BeginUpdate();

            var treeListNode = parentNode.AddOrUpdateChild(new object[] { modelElement.Name }, modelElement, IsThisModelInfoCatalog);
            treeListNode.SetSelectImage(Resources.objects);
            treeListNode.SetImage(Resources.objects);

            parentNode.TreeList.EndUpdate();

            return treeListNode;
        }

        /// <summary>
        /// Adds the or update tree list node.
        /// </summary>
        /// <param name="parentNode">The parent node.</param>
        /// <param name="modelInfos">The model infos.</param>
        /// <returns>TreeListNode.</returns>
        public static void AddOrUpdateTreeListNode(TreeListNode parentNode, IList<ModelElement> modelInfos)
        {
            if (parentNode == null)
                return;

            parentNode.TreeList.BeginUpdate();

            foreach (var modelElement in modelInfos)
            {
                var treeListNode = parentNode.AddOrUpdateChild(new object[] { modelElement.Name }, modelElement, IsThisModelInfoCatalog);
                treeListNode.SetSelectImage(Resources.objects);
                treeListNode.SetImage(Resources.objects);
            }

            parentNode.TreeList.EndUpdate();
        }

        /// <summary>
        /// Determines whether [is this model information catalog] [the specified node].
        /// </summary>
        /// <param name="node">The node.</param>
        /// <param name="tag">The tag.</param>
        /// <returns><c>true</c> if [is this model information catalog] [the specified node]; otherwise, <c>false</c>.</returns>
        private static bool IsThisModelInfoCatalog(TreeListNode node, object tag)
        {
            var oldCatalog = node.Tag as ModelElement;
            var newCatalog = tag as ModelElement;
            if (oldCatalog == null || newCatalog == null)
                return false;
            return oldCatalog.ModelElementId == newCatalog.ModelElementId;
        }

        /// <summary>
        /// Adds the or update tree node.
        /// </summary>
        /// <param name="treeListNode">The tree list node.</param>
        /// <param name="userProject">The user project.</param>
        public static void AddOrUpdateTreeNode(TreeListNode treeListNode, Project userProject)
        {
            var node = treeListNode.AddOrUpdateChild(userProject.Name, userProject, IsThisProjectTreeListNodeEvent);
            node.SetSelectImage(Resources.项目);
        }

        /// <summary>
        /// Determines whether [is this project tree list node event] [the specified node].
        /// </summary>
        /// <param name="node">The node.</param>
        /// <param name="tag">The tag.</param>
        /// <returns><c>true</c> if [is this project tree list node event] [the specified node]; otherwise, <c>false</c>.</returns>
        private static bool IsThisProjectTreeListNodeEvent(TreeListNode node, object tag)
        {
            var oldProject = node.Tag as Project;
            var newProject = tag as Project;
            return oldProject.ProjectId == newProject.ProjectId;
        }

        /// <summary>
        /// Adds the or update tree node.
        /// </summary>
        /// <param name="treeListNode">The tree list node.</param>
        /// <param name="userGroup">The user group.</param>
        public static void AddOrUpdateTreeNode(TreeListNode treeListNode, ModelGrope userGroup)
        {
            var node = treeListNode.AddOrUpdateChild(userGroup.Name, userGroup, IsThisUserGroupTreeListNodeEvent);
            node.SetSelectImage(Resources.分组);
        }

        /// <summary>
        /// Adds the or update tree node.
        /// </summary>
        /// <param name="treeListNode">The tree list node.</param>
        /// <param name="userModel">The user model.</param>
        public static void AddOrUpdateTreeNode(TreeListNode treeListNode, ModelElement userModel, bool bCheck)
        {
            var node = treeListNode.AddOrUpdateChild(userModel.Name, userModel, IsThisUserModelTreeListNodeEvent);
            node.Checked = bCheck;
            node.SetImage(Resources.模型编辑);
            node.SetSelectImage(Resources.模型编辑);
        }

        /// <summary>
        /// Determines whether [is this group tree list node event] [the specified node].
        /// </summary>
        /// <param name="node">The node.</param>
        /// <param name="tag">The tag.</param>
        /// <returns><c>true</c> if [is this group tree list node event] [the specified node]; otherwise, <c>false</c>.</returns>
        private static bool IsThisUserGroupTreeListNodeEvent(TreeListNode node, object tag)
        {
            var oldGroup = node.Tag as ModelGrope;
            var newGroup = tag as ModelGrope;
            return oldGroup.ModelGropeId == newGroup.ModelGropeId;
        }

        /// <summary>
        /// Determines whether [is this user model tree list node event] [the specified node].
        /// </summary>
        /// <param name="node">The node.</param>
        /// <param name="tag">The tag.</param>
        /// <returns><c>true</c> if [is this user model tree list node event] [the specified node]; otherwise, <c>false</c>.</returns>
        private static bool IsThisUserModelTreeListNodeEvent(TreeListNode node, object tag)
        {
            var oldUserModel = node.Tag as ModelElement;
            var newUserModel = tag as ModelElement;
            return oldUserModel.ModelElementId == newUserModel.ModelElementId;
        }


        /// <summary>
        /// Project
        /// </summary>
        /// <param name="userProject">The user project.</param>
        public static void AddOrUpdateTreeNode(this Project userProject)
        {
            var rootNode = TreeList.Nodes.GetNodeByDisplayText("模型");
            AddOrUpdateTreeNode(rootNode, userProject);
        }

        /// <summary>
        /// 添加分组节点
        /// </summary>
        /// <param name="userGroup">The user group.</param>
        public static void AddOrUpdateTreeNode(this ModelGrope userGroup)
        {
            var treeNodeNode = userGroup.GetProject().GetUserProjectTreeNode();
            AddOrUpdateTreeNode(treeNodeNode, userGroup);
        }

        /// <summary>
        /// Adds the or update tree node.
        /// </summary>
        /// <param name="userModel">The user model.</param>
        /// <param name="bCheck">if set to <c>true</c> [b check].</param>
        public static void AddOrUpdateTreeNode(this ModelElement userModel, bool bCheck = true)
        {
            var treeNodeNode = userModel.GetModelGrope().GetUserGroupTreeNode();
            AddOrUpdateTreeNode(treeNodeNode, userModel, bCheck);
        }

        /// <summary>
        /// 删除项目节点
        /// </summary>
        /// <param name="userProject">The user project.</param>
        public static void DeleteTreeNode(this Project userProject)
        {
            TreeList.BeginUpdate();
            var treeNode = userProject.GetUserProjectTreeNode();
            treeNode.ParentNode.Nodes.Remove(treeNode);
            TreeList.EndUpdate();
        }

        /// <summary>
        /// 删除分组节点
        /// </summary>
        /// <param name="userGroup">The user group.</param>
        public static void DeleteTreeNode(this ModelGrope userGroup)
        {
            TreeList.BeginUpdate();
            var treeNode = userGroup.GetUserGroupTreeNode();
            treeNode.ParentNode.Nodes.Remove(treeNode);
            TreeList.EndUpdate();
        }

        /// <summary>
        /// Deletes the tree node.
        /// </summary>
        /// <param name="userModel">The user model.</param>
        public static void DeleteTreeNode(this ModelElement userModel)
        {
            TreeList.BeginUpdate();
            var treeNode = userModel.GetUserModelTreeNode();
            treeNode.ParentNode.Nodes.Remove(treeNode);
            TreeList.EndUpdate();
        }

        /// <summary>
        /// 得到项目节点
        /// </summary>
        /// <param name="userProject">The user project.</param>
        /// <returns>TreeListNode.</returns>
        public static TreeListNode GetUserProjectTreeNode(this Project userProject)
        {
            var rootNode = TreeList.Nodes.GetNodeByDisplayText("模型");
            return rootNode.Nodes.GetNode(userProject, IsThisProjectTreeListNodeEvent);
        }

        /// <summary>
        /// 得到分组节点
        /// </summary>
        /// <param name="userGroup">The user group.</param>
        /// <returns>TreeListNode.</returns>
        public static TreeListNode GetUserGroupTreeNode(this ModelGrope userGroup)
        {
            var treeNodeNode = userGroup.GetProject().GetUserProjectTreeNode();
            return treeNodeNode.Nodes.GetNode(userGroup, IsThisUserGroupTreeListNodeEvent);
        }

        /// <summary>
        /// Gets the user model tree node.
        /// </summary>
        /// <param name="userModel">The user model.</param>
        /// <returns>TreeListNode.</returns>
        public static TreeListNode GetUserModelTreeNode(this ModelElement userModel)
        {
            var treeNodeNode = userModel.GetModelGrope().GetUserGroupTreeNode();
            return treeNodeNode.Nodes.GetNode(userModel, IsThisUserModelTreeListNodeEvent);
        }


        /// <summary>
        /// Shows the current group tree node.
        /// </summary>
        public static void ShowCurGroupTreeNode()
        {
            if (CurUserGroup.Instance.ModelGrope != null)
            {
                ShowTreeListNode(CurUserGroup.Instance.ModelGrope);
            }
            else if (CurUserGroup.Instance.Project != null)
            {
                ShowTreeListNode(CurUserGroup.Instance.Project);
            }

        }

        /// <summary>
        /// Shows the tree list node.
        /// </summary>
        /// <param name="userGroup">The user group.</param>
        public static void ShowTreeListNode(ModelGrope userGroup)
        {
            ShowTreeListNode(GetUserGroupTreeNode(userGroup));
        }

        /// <summary>
        /// Shows the tree list node.
        /// </summary>
        /// <param name="userProject">The user project.</param>
        public static void ShowTreeListNode(Project userProject)
        {
            ShowTreeListNode(GetUserProjectTreeNode(userProject));
        }

        /// <summary>
        /// Shows the tree list node.
        /// </summary>
        /// <param name="treeNode">The tree node.</param>
        public static void ShowTreeListNode(TreeListNode treeNode)
        {
            if (treeNode == null)
            {
                return;
            }
            TreeList.BeginUpdate();
            while (treeNode != null)
            {
                treeNode.Expanded = true;
                treeNode = treeNode.ParentNode;
            }
            TreeList.EndUpdate();
        }

        /// <summary>
        /// Trees the list on node cell style.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="args">The <see cref="GetCustomNodeCellStyleEventArgs" /> instance containing the event data.</param>
        public static void BmTreeListOnNodeCellStyle(object sender, GetCustomNodeCellStyleEventArgs args)
        {
            if (args.Node.Tag is Project)
            {
                Project userProject = args.Node.Tag as Project;
                if (CurUserGroup.Instance != null 
                    && CurUserGroup.Instance.Project != null 
                    && userProject.ProjectId == CurUserGroup.Instance.Project.ProjectId)
                {
                    args.Appearance.ForeColor = Color.Red;
                }
            }
            else if (args.Node.Tag is ModelGrope)
            {
                var userGroup = args.Node.Tag as ModelGrope;
                if (CurUserGroup.Instance != null 
                    && CurUserGroup.Instance.ModelGrope != null 
                    && userGroup.ModelGropeId == CurUserGroup.Instance.ModelGrope.ModelGropeId)
                {
                    args.Appearance.ForeColor = Color.Red;
                }
            }
        }
    }
}
